﻿using System;
using System.Collections;
using System.Web;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using DVK.SP2007.Constants;
using DVK.SP2007.Controls;
using DVK.SP2007.Resources;
using DVK.SP2007.UniversalClient;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;

namespace DVK.SP2007.Pages
{
    /// <summary>
    /// MoveDocument page allowes moving DVK message into a Document Library as a document.
    /// </summary>
    public partial class MoveDocument : LayoutsPageBase
    {
        private string _itemUrl;
        private SPWeb _web;
        private SPListItem _item;

        /// <summary>
        /// Gets the source item for the move.
        /// </summary>
        /// <value>DVK message item from inbox list</value>
        protected SPListItem SourceItem
        {
            get
            {
                if (_item == null)
                    _item = _web.GetListItem(_itemUrl);
                return _item;
            }
        }

        #region Events

        /// <summary>
        /// Handles the Load event of the Page control.
        /// <remarks>
        /// Loads default information to controls.
        /// </remarks>
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            _itemUrl = Request.Params[Params.QueryStringParameterItemUrl];
            _web = SPContext.Current.Web;

            if (!this.IsPostBack)
            {
                lblItemUrl.Text = _itemUrl;
                FillDocumentLibraryLocations();
            }
        }

        /// <summary>
        /// Handles the Click event of the btnMove control.
        /// 
        /// <remarks>
        /// Contains the logic for moving the DVK message item to a Document Library.
        /// </remarks>
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void btnMove_Click(object sender, EventArgs e)
        {
            //Server side validation for action: Move
            if (string.IsNullOrEmpty(ddlDocLibLocations.SelectedValue) ||
                string.IsNullOrEmpty(ddlContentTypes.SelectedValue))
            {
                ShowError(DvkWeb.MoveDocument_ErrorFolderAndType);
                return;
            }

            bool redirect = true;

            SPFile sourceFile = SourceItem.File;

            SPFolder targetFolder = _web.GetFolder(ddlDocLibLocations.SelectedValue);
            SPList targetList = _web.Lists[targetFolder.ContainingDocumentLibrary];

            var newFileProperties = new Hashtable
                                 {
                                    { Constants.FieldNames.SPFileContentTypeIdProperty, ddlContentTypes.SelectedItem.Value }
                                 };
            string targetUrl = InboxOutboxItemHelper.RemoveDateTimeFromTargetUrl(targetFolder.ServerRelativeUrl + "/" + SourceItem.Name);

            //Start moving
            SPFile newFile = null;
            try
            {
                //Adds new version, if existing is there or overwrites the old one!
                newFile = targetFolder.Files.Add(
                            targetUrl, sourceFile.OpenBinaryStream(), newFileProperties, true);
            }
            catch (Exception exc)
            {
                ShowError(DvkWeb.MoveDocument_ErrorFailedToMove, exc.ToString());
                return;
            }
            //Mapping metadata from DVK message to new item
            SPListItem newItem = newFile.Item;

            try
            {
                //TODO: THis must later consider ContentType and List level mappings (Taavi, Date)
                var mappings =
                    new MetadataMappingRepository(_web)
                        .GetMapping(
                            Fields.DvkMappingLevel.DvkMappingLevelChoices.Web,
                            null,
                            Fields.DvkMappingApplyingTo.DvkMappingApplyingToChoices.In);

                DvkXml dvkXml =
                    new DvkXml(
                                GetItemValue(SourceItem, Fields.DvkMetainfoXml.Name),
                                GetItemValue(SourceItem, Fields.DvkTransportXml.Name),
                                GetItemValue(SourceItem, Fields.DvkMetaXml.Name)
                            );

                foreach (var mapping in mappings)
                {
                    SPField field = newItem.Fields.GetFieldByInternalName(mapping.SPFieldName);
                    if (field == null)
                        continue;

                    var elementValue = dvkXml.GetElementValue(mapping.DvkParentElementName, mapping.DvkElementName);
                    if (string.IsNullOrEmpty(elementValue))
                        continue;

                    switch (field.Type)
                    {
                        case SPFieldType.Boolean:
                            {
                                bool temp;
                                if (bool.TryParse(elementValue, out temp))
                                    newItem[mapping.SPFieldName] = temp;
                                break;
                            }
                        case SPFieldType.DateTime:
                            {
                                DateTime temp;
                                if (DateTime.TryParse(elementValue, out temp))
                                    newItem[mapping.SPFieldName] = temp;
                                break;
                            }
                        case SPFieldType.Integer:
                            {
                                int temp;
                                if (int.TryParse(elementValue, out temp))
                                    newItem[mapping.SPFieldName] = temp;
                                break;
                            }
                        default:
                            {
                                newItem[mapping.SPFieldName] = elementValue;
                                break;
                            }
                    }
                }

                newItem.UpdateOverwriteVersion();
            }
            catch (Exception exc)
            {
                ShowError(DvkWeb.MoveDocument_ErrorFailedToMapMetadata, exc.ToString());
                redirect = false;
            }

            //Updating Inbox CurrentItem, so there would be indication that it has been moved.
            SourceItem[Fields.DocumentLibraryItemId.Name] = newItem.ID;
            SourceItem.Update();

            if (redirect)
            {
                SPUtility.Redirect(targetFolder.ServerRelativeUrl, SPRedirectFlags.Default, HttpContext.Current);
            }
        }
        /// <summary>
        /// Handles the OnSelectedIndexChanged event of the ddlDocLibLocations control.
        /// <remarks>
        /// Happens when the user picks new location from ddlDocLibLocations dropdownlist.
        /// The locations are configured from the DvkSettings list.
        /// </remarks>
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void ddlDocLibLocations_OnSelectedIndexChanged(object sender, EventArgs e)
        {
            var mappedMetadataViewer = this.mappedMetadata as MappedMetadataViewer;

            //If DocumentLibrary location is "", then we cant look up contenttypes
            if (string.IsNullOrEmpty(ddlDocLibLocations.SelectedItem.Value))
            {
                //Empty the metadataviewer information
                mappedMetadataViewer.MappedMetadataProvider = null;
                mappedMetadataViewer.RefreshMetadata();
                return;
            }

            string selectedValue = this.ddlDocLibLocations.SelectedItem.Value;

            SPFolder folder = _web.GetFolder(selectedValue);
            SPList targetList = _web.Lists[folder.ContainingDocumentLibrary];

            //Empty existing contenttype list and add new contenttypes
            this.ddlContentTypes.Items.Clear();

            foreach (SPContentType contentType in targetList.ContentTypes)
            {
                this.ddlContentTypes.Items.Add(new ListItem(contentType.Name, contentType.Id.ToString()));
            }

            //Add information to MappedDataViewer to show mapped metadata
            DvkXml dvkXml = new DvkXml(
                    GetItemValue(SourceItem, Fields.DvkMetainfoXml.Name),
                    GetItemValue(SourceItem, Fields.DvkMetaXml.Name),
                    GetItemValue(SourceItem, Fields.DvkTransportXml.Name)
                );
            mappedMetadataViewer.MappedMetadataProvider = new InMappedMetadataProvider(targetList.Fields, dvkXml);
            mappedMetadataViewer.RefreshMetadata();
        }

        #endregion

        /// <summary>
        /// Fills the dropdownlist of document library locations.
        /// <remarks>
        /// The document library locations are loaded from DvkSettings list. There's a setting called 'DvkMoveToDocumentLibaryPaths'.
        /// The value is a text containing a list of locations separated by ';'.
        /// </remarks>
        /// </summary>
        private void FillDocumentLibraryLocations()
        {
            DvkSettingsRepository settingsManager = new DvkSettingsRepository(_web);
            var dvkMoveToDocumentLibraryPaths =
                settingsManager.GetSetting(Settings.DvkMoveToDocumentLibaryPaths);

            string[] paths = dvkMoveToDocumentLibraryPaths.Split(';');

            //Empty element in the list
            ddlDocLibLocations.Items.Add(new ListItem("", ""));

            foreach (var path in paths)
            {
                ddlDocLibLocations.Items.Add(new ListItem(path));
            }
        }

        /// <summary>
        /// Gets the field value from item as XElement.
        /// </summary>
        /// <param name="item">The sharepoint listitem.</param>
        /// <param name="fieldName">Name of the field.</param>
        /// <returns>if not null then XElement, otherwise null</returns>
        private static XElement GetItemValue(SPListItem item, string fieldName)
        {
            return (item[fieldName] != null ? XElement.Parse(item[fieldName] as string) : null);
        }

        /// <summary>
        /// Shows the error in the lbErrorMessage.
        /// </summary>
        /// <param name="error">The error.</param>
        /// <param name="additional">The additional.</param>
        private void ShowError(string error, params object[] additional)
        {
            lbErrorMessage.Text = string.Format(error, additional);
        }
    }
}
